"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments)).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
    return { next: verb(0), "throw": verb(1), "return": verb(2) };
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [0, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var mongoose = require("mongoose");
var Room = require("./room");
;
exports.Schema = new mongoose.Schema({
    platform: String,
    openId: String,
    name: String,
    iconPath: String,
    isMale: Boolean,
    customData: {
        name: String,
        isMale: Boolean,
        iconPath: String,
    },
    ip: String,
    skin: { type: Number, default: 0 },
    skins: { type: [Number], default: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] },
    theme: { type: Number, default: 0 },
    themes: { type: [Number], default: [1] },
    role: String,
    level: { type: Number, default: 1 },
    xp: { type: Number, default: 0 },
    popularity: { type: Number, default: 0 },
    credits: { type: Number, default: 0 },
    givenPopularity: { type: Number, default: 0 },
    title: String,
    titles: [String],
    signInDays: { type: Number, default: 0 },
    signInAt: { type: Number, default: 0 },
    gifts: [{
            id: Number,
            amount: Number,
            _id: false,
        }],
    inventory: [{
            id: Number,
            amount: { type: Number, default: 1 },
            _id: false,
        }],
    currencys: {
        gold: { type: Number, default: 0 },
    },
    roleRecords: [{
            role: String,
            wins: Number,
            loses: Number,
            _id: false,
        }],
    dailyTask: {
        clears: [Number],
        roleRecords: [{
                role: String,
                wins: Number,
                loses: Number,
                _id: false,
            }],
    },
    lastGiftRecord: { type: mongoose.Schema.Types.ObjectId, ref: "GiftRecord" },
    // 直播
    isAnchor: Boolean,
    coverUrl: String,
    following: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
    maxGroups: [{ type: Number, default: 5 }],
    addressInfo: {
        name: String,
        phone: String,
        address: String,
    },
});
exports.Model = mongoose.model("User", exports.Schema);
function findRooms(uid) {
    return __awaiter(this, void 0, void 0, function () {
        var rooms, viewerRooms, i;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, Room.Model.find({
                        "players": {
                            $elemMatch: {
                                "user._id": uid,
                            },
                        }
                    })];
                case 1:
                    rooms = _a.sent();
                    return [4 /*yield*/, Room.Model.find({
                            "viewers": {
                                $in: [uid],
                            }
                        })];
                case 2:
                    viewerRooms = _a.sent();
                    for (i = 0; i < viewerRooms.length; i++) {
                        rooms.push(viewerRooms[i]);
                    }
                    return [2 /*return*/, rooms];
            }
        });
    });
}
exports.findRooms = findRooms;
;
function findRoom(uid) {
    return __awaiter(this, void 0, void 0, function () {
        var room, viewerRoom;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, Room.Model.findOne({
                        "players": {
                            $elemMatch: {
                                "user._id": uid,
                            },
                        }
                    })];
                case 1:
                    room = _a.sent();
                    if (!!room) {
                        return [2 /*return*/, room];
                    }
                    return [4 /*yield*/, Room.Model.findOne({
                            "viewers": {
                                $in: [uid],
                            }
                        })];
                case 2:
                    viewerRoom = _a.sent();
                    return [2 /*return*/, viewerRoom];
            }
        });
    });
}
exports.findRoom = findRoom;
;
function leaveRoom(app, user, room, isInitiative) {
    return __awaiter(this, void 0, void 0, function () {
        var player;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, Room.viewerLeave(app, room, user)];
                case 1:
                    room = _a.sent();
                    if (!((room.isLive && !isInitiative) || room.isStart))
                        return [3 /*break*/, 3];
                    player = room.players.find(function (p) { return !!p && p.user._id.equals(user._id); });
                    if (player)
                        player.isOnline = false;
                    return [4 /*yield*/, Room.sync(app, room)];
                case 2:
                    room = _a.sent();
                    return [3 /*break*/, 5];
                case 3: return [4 /*yield*/, Room.playerLeave(app, room, user)];
                case 4:
                    room = _a.sent();
                    _a.label = 5;
                case 5: return [4 /*yield*/, pushMessage(app, user._id.toString(), "onSyncRoom", {})];
                case 6:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
exports.leaveRoom = leaveRoom;
function sync(app, user) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, user.save()];
                case 1:
                    user = _a.sent();
                    return [4 /*yield*/, pushMessage(app, user._id.toString(), "onSyncUser", user)];
                case 2:
                    _a.sent();
                    return [2 /*return*/, user];
            }
        });
    });
}
exports.sync = sync;
function pushMessage(app, uid, route, message) {
    var _this = this;
    return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
        var statusService;
        return __generator(this, function (_a) {
            statusService = app.get('statusService');
            statusService.pushByUids([uid], route, message, function (err, fails) {
                resolve();
            });
            return [2 /*return*/];
        });
    }); });
}
exports.pushMessage = pushMessage;
function gameResult(app, uid, role, isWin, xp) {
    return __awaiter(this, void 0, void 0, function () {
        var user;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, exports.Model.findById(uid).exec()];
                case 1:
                    user = _a.sent();
                    if (!user)
                        return [2 /*return*/, user];
                    if (!role)
                        return [2 /*return*/, user];
                    user = addXp(user, xp);
                    user = addRoleRecord(user, role, isWin);
                    return [4 /*yield*/, sync(app, user)];
                case 2:
                    user = _a.sent();
                    return [2 /*return*/, user];
            }
        });
    });
}
exports.gameResult = gameResult;
function addXp(user, xp) {
    user.xp += xp;
    if (user.level > 0 && user.level < 60) {
        var levelUpXp = user.level * 125;
        while (user.xp >= levelUpXp) {
            user.level++;
            user.xp -= levelUpXp;
            levelUpXp = user.level * 125;
        }
    }
    return user;
}
function addRoleRecord(user, role, isWin) {
    var updateRecord = function (records) {
        var roleRecord = records.find(function (r) { return r.role == role; });
        if (!roleRecord) {
            roleRecord = {
                role: role,
                wins: isWin ? 1 : 0,
                loses: !isWin ? 1 : 0,
            };
            records.push(roleRecord);
        }
        else {
            if (isWin)
                roleRecord.wins++;
            else
                roleRecord.loses++;
        }
    };
    updateRecord(user.roleRecords);
    updateRecord(user.dailyTask.roleRecords);
    return user;
}
function canClearDailyTask(user, task) {
    if (user.dailyTask.clears.indexOf(task.id) >= 0)
        return false;
    var isClear = getTaskAmount(user, task) >= task.amount;
    // let isClear = eval(task.func);
    if (!isClear)
        return false;
    return true;
}
exports.canClearDailyTask = canClearDailyTask;
function getTaskAmount(user, task) {
    if (task.role) {
        var record = user.dailyTask.roleRecords.find(function (r) { return r.role == task.role; });
        return !!record ? record.wins : 0;
    }
    else {
        var allWins = 0;
        for (var i = 0; i < user.dailyTask.roleRecords.length; i++) {
            allWins += user.dailyTask.roleRecords[i].wins;
        }
        return allWins;
    }
}
exports.getTaskAmount = getTaskAmount;
function clearDailyTask(user, task) {
    user.dailyTask.clears.push(task.id);
    ;
    user = addItems(user, task.rewards);
    return user;
}
exports.clearDailyTask = clearDailyTask;
function addItems(user, items) {
    for (var i = 0; i < items.length; i++) {
        var item = items[i];
        user = addItem(user, item.id, item.amount);
    }
    return user;
}
exports.addItems = addItems;
function addGift(user, itemId) {
    var item = user.gifts.find(function (i) { return i.id == itemId; });
    if (item) {
        item.amount += 1;
    }
    else {
        item = {
            id: itemId,
            amount: 1,
        };
        user.gifts.push(item);
    }
    return user;
}
exports.addGift = addGift;
function addItem(user, itemId, amount) {
    //增加钻石
    if (itemId == 15) {
        user.currencys.gold += amount;
        return user;
    }
    // 增加积分
    if (itemId == 16) {
        user.credits += amount;
        return user;
    }
    var item = user.inventory.find(function (i) { return i.id == itemId; });
    if (item) {
        item.amount += amount;
    }
    else {
        item = {
            id: itemId,
            amount: amount,
        };
        user.inventory.push(item);
    }
    return user;
}
exports.addItem = addItem;
function removeItem(user, itemId, amount) {
    if (itemId == 15) {
        user.currencys.gold -= amount;
        return user;
    }
    var itemIndex = user.inventory.findIndex(function (i) { return i.id == itemId; });
    if (itemIndex >= 0) {
        var item = user.inventory[itemIndex];
        item.amount -= amount;
        if (item.amount <= 0) {
            user.inventory.splice(itemIndex, 1);
        }
    }
    return user;
}
exports.removeItem = removeItem;
function getName(user) {
    return user.customData.name ? user.customData.name : user.name;
}
exports.getName = getName;
function getIconPath(user) {
    return user.customData.iconPath ? user.customData.iconPath : user.iconPath;
}
exports.getIconPath = getIconPath;
function getIsMale(user) {
    return user.customData.isMale ? user.customData.isMale : user.isMale;
}
exports.getIsMale = getIsMale;
// 插入更新收货地址信息
// addressInfo:{
// 		name:string;
// 		phone:string;
// 		address:string;
// 	}
function insertOrUpdateAddressInfo(uid, name, phone, address) {
    return __awaiter(this, void 0, void 0, function () {
        var AddressInfo;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, exports.Model.findOneAndUpdate({ _id: uid }, {
                        $set: {
                            name: name,
                            phone: phone,
                            address: address,
                        },
                    }, {
                        upsert: true,
                    })];
                case 1:
                    AddressInfo = _a.sent();
                    return [2 /*return*/, AddressInfo];
            }
        });
    });
}
exports.insertOrUpdateAddressInfo = insertOrUpdateAddressInfo;
